package com.alibaba.springbootrbac.service.impl;

import com.alibaba.springbootrbac.mapper.PermissionMapper;
import com.alibaba.springbootrbac.mapper.UserMapper;
import com.alibaba.springbootrbac.mapper.UserRoleMapper;
import com.alibaba.springbootrbac.model.entity.Role;
import com.alibaba.springbootrbac.model.entity.User;
import com.alibaba.springbootrbac.model.param.user.*;
import com.alibaba.springbootrbac.model.response.permission.PermissionVO;
import com.alibaba.springbootrbac.model.response.role.RoleVO;
import com.alibaba.springbootrbac.model.response.user.UserInfoVO;
import com.alibaba.springbootrbac.model.response.user.UserLoginVO;
import com.alibaba.springbootrbac.model.response.user.UserRegisterVO;
import com.alibaba.springbootrbac.service.UserService;
import com.alibaba.springbootrbac.utils.BizException;
import com.alibaba.springbootrbac.utils.jwt.JwtUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author ZhouYaDong
 * @date 2025/8/21
 * @description
 */
@Transactional(rollbackFor = Exception.class) // 表示出现任何异常都会回滚
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private UserRoleMapper userRoleMapper;

    @Resource
    private UserRoleMapper userRoleService;

    @Resource
    private RedisTemplate<String,Object> redisTemplate;


    @Value("${jwt.expire-hours}")
    private int expireHours;  // token过期时间
    @Autowired
    private PermissionMapper permissionMapper;

    @Override
    public UserRegisterVO register(UserRegisterParam param) {

        // 校验唯一性
        checkUnique("username", param.getUsername(), "注册失败，用户名已被注册");
        checkUnique("phone", param.getPhone(), "注册失败，手机号已被注册");
        checkUnique("email", param.getEmail(), "注册失败，邮箱已被注册");

        // 将param转换成实体类
        User user = new User();
        user.setUsername(param.getUsername());

        // 对密码进行加密 todo 生产环境建议使用BCrypt
        user.setPassword(param.getPassword());

        user.setPhone(param.getPhone());
        user.setEmail(param.getEmail());
        // 注册的新账户默认为禁用中，后续使用邮箱进行激活
        user.setStatus(0);
        // 写入数据库
        int insert = userMapper.insert(user);
        if (insert == 0){
            throw new BizException("用户注册失败，userMapper将数据写入DB时出现异常");
        }

        UserRegisterVO userRegisterVO = new UserRegisterVO();
        userRegisterVO.setId(user.getId());
        userRegisterVO.setUsername(user.getUsername());
        userRegisterVO.setPhone(user.getPhone());
        userRegisterVO.setEmail(user.getEmail());
        userRegisterVO.setStatus(0);
        userRegisterVO.setRegisterTime(user.getCreateTime());
        return userRegisterVO;
    }

    @Override
    public UserLoginVO login(UserLoginParam param) {
        QueryWrapper<User> loginQueryWrapper = new QueryWrapper<>();
        loginQueryWrapper.eq("username", param.getAccount())
                .or()
                .eq("phone", param.getAccount())
                .or()
                .eq("email", param.getAccount());

        User user = userMapper.selectOne(loginQueryWrapper);

        if (user == null) {
            throw new BizException("账户不存在");
        }

        // 密码校验（建议生产用 BCrypt）todo 生产环境建议使用BCrypt
        if (!param.getPassword().equals(user.getPassword())){
            throw new BizException("密码错误");
        }

        UserLoginVO userLoginVO = new UserLoginVO();

        // 查询用户的角色和状态
        List<RoleVO> roles = userRoleService.selectRolesByUserId(user.getId()).stream().map(
                role -> {
                    RoleVO roleVO = new RoleVO();
                    BeanUtils.copyProperties(role, roleVO);
                    return roleVO;
                }
        ).toList();

        List<PermissionVO> permissionVOS = permissionMapper.selectPermissionsByUserId(user.getId())
                .stream()
                .map(permission -> {
                    PermissionVO permissionVO = new PermissionVO();
                    BeanUtils.copyProperties(permission, permissionVO);
                    return permissionVO;
                })
                .toList();

        userLoginVO.setRoles(roles);
        userLoginVO.setPermissions(permissionVOS);

        // 生成 JWT Token
        String token = JwtUtils.sign(user.getId(), user.getUsername());

        log.info("登录成功，token: {}", token);

        LocalDateTime loginTime = LocalDateTime.now();
        LocalDateTime tokenExpireTime = loginTime.plusHours(expireHours);

        userLoginVO.setId(user.getId());
        userLoginVO.setUsername(user.getUsername());
        userLoginVO.setEmail(user.getEmail());
        userLoginVO.setPhone(user.getPhone());
        userLoginVO.setStatus(user.getStatus());
        userLoginVO.setToken(token);
        userLoginVO.setLoginTime(loginTime); // 登录时间
        userLoginVO.setTokenExpireTime(tokenExpireTime);
        return userLoginVO;
    }

    @Override
    public void logout(String token) {
    }

    @Override
    public User queryByUserName(String username) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        return userMapper.selectOne(queryWrapper);
    }

    @Override
    public void deleteUserById(String id) {
        // 逻辑删除
        int i = userMapper.deleteById(id);
        if (i == 0){
            throw new BizException("用户信息删除失败，ID："+id);
        }
    }

    @Override
    public void deleteUserByIds(List<String> ids) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", ids);
        int delete = userMapper.delete(queryWrapper);
        if (delete != ids.size()){
            throw new BizException("批量删除用户信息失败,事务已经回滚，ids"+ids);
        }
    }

    @Override
    public void updateUserById(UpdateUserParam param) {
        if (param.getId() == null){
            throw new BizException("更新失败，ID字段为空");
        }
        // 更新之前查询出DB中最新的结果
        User user = userMapper.selectById(param.getId());

        if (user == null) {
            throw new BizException("更新失败，ID=" + param.getId() + "，未找到该用户");
        }

        // 自动拷贝同名属性
        BeanUtils.copyProperties(param, user);

        // 对密码进行加密 todo 生产环境建议使用BCrypt

        System.out.println("user:"+user);
        int i = userMapper.updateById(user);
        if (i == 0){
            throw new BizException("更新失败，ID=" + param.getId());
        }
    }

    @Override
    public UserInfoVO getUserInfoById(String id) {
        User user = userMapper.selectById(id);
        // 对查询结果进行判空
        if (user == null) {
            throw new BizException("用户不存在或者已经被删除，ID=" + id);
        }
        // 将user转化成UserInfoVO
        UserInfoVO userInfoVO = new UserInfoVO();
        BeanUtils.copyProperties(user, userInfoVO);
        return userInfoVO;
    }

    @Override
    public IPage<UserInfoVO> getUsersInfoByPage(UserPageQueryParam pageQueryParam) {
        //  对输入的参数进行非空校验和初始化赋值
        int current = pageQueryParam.getPageNum() != null && pageQueryParam.getPageNum() > 0 ? pageQueryParam.getPageNum() : 1;
        int size = pageQueryParam.getPageSize() != null && pageQueryParam.getPageSize() > 0 ? pageQueryParam.getPageSize() : 10;

        // 创建分页查询的page对象
        Page<User> page = new Page<>(current, size);

        // 基于传入的条件，动态构建查询条件
        QueryWrapper<User> userQueryWrapper = convertToQueryWrapper(pageQueryParam);

        // 执行查询
        IPage<User> page1 = userMapper.selectPage(page, userQueryWrapper);
        log.info("page1: {}", page1);

        // j将IPage转换成VO
        return convertToVOPage(page1);
    }

    @Override
    public void assignRolesToUser(UserRoleParam param) {
        // 删除用户已有的角色关联
        userRoleMapper.deleteByUserId(param.getUserId());

        // 批量插入新的角色关联
        int i = userRoleMapper.insertUserRoles(param.getUserId(), param.getRoleIds());
        if (i != param.getRoleIds().size()){
            throw new BizException("给用户分配角色失败，事务已经回滚，param"+param);
        }
    }

    @Override
    public void removeUserRoles(UserRoleParam param) {
        int i = userRoleMapper.deleteUserRolesBatch(param.getUserId(), param.getRoleIds());
        if (i != param.getRoleIds().size()){
            throw new BizException("删除用户角色关联关系失败，事务已经回滚，param"+param);
        }
    }

    @Override
    public List<String> getUserPermissions(String userId) {
        return List.of();
    }

    @Override
    public List<Role> getUserRoles(String userId) {
        return userRoleMapper.selectRolesByUserId(userId);
    }

    // 校验数据库中是否已经存在
    private void checkUnique(String column, String value, String message) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq(column, value).last("LIMIT 1");
        if (userMapper.selectOne(wrapper) != null) {
            throw new BizException(message);
        }
    }

    /**
     * 动态生成 QueryWrapper
     * @param param 分页查询参数
     * @return QueryWrapper 查询条件构造器
     */
    public static QueryWrapper<User> convertToQueryWrapper(UserPageQueryParam param) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();

        // 页码和每页条数已经在业务逻辑中处理，无需在 QueryWrapper 中考虑

        // 用户名条件（如果不为空则加入查询条件）
        if (StringUtils.isNotBlank(param.getUsername())) {
            queryWrapper.like("username", param.getUsername());
        }

        // 状态条件（如果不为空则加入查询条件）
        if (param.getStatus() != null) {
            queryWrapper.eq("status", param.getStatus());
        }

        // 手机号条件（如果不为空则加入查询条件）
        if (StringUtils.isNotBlank(param.getPhone())) {
            queryWrapper.eq("phone", param.getPhone());
        }

        // 邮箱条件（如果不为空则加入查询条件）
        if (StringUtils.isNotBlank(param.getEmail())) {
            queryWrapper.eq("email", param.getEmail());
        }

        return queryWrapper;
    }

    public static IPage<UserInfoVO> convertToVOPage(IPage<User> userPage) {
        List<UserInfoVO> userInfoVOList = userPage.getRecords().stream()
                .map(user -> {
                    UserInfoVO userInfoVO = new UserInfoVO();
                    userInfoVO.setId(user.getId());
                    userInfoVO.setUsername(user.getUsername());
                    userInfoVO.setPhone(user.getPhone());
                    userInfoVO.setEmail(user.getEmail());
                    userInfoVO.setStatus(user.getStatus());
                    return userInfoVO;
                })
                .collect(Collectors.toList());

        IPage<UserInfoVO> result = new Page<>();
        result.setRecords(userInfoVOList);
        result.setTotal(userPage.getTotal());
        result.setSize(userPage.getSize());
        result.setCurrent(userPage.getCurrent());
        return result;
    }

}
